package com.example.mydemo.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Console;
import cn.hutool.cron.CronUtil;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import cn.hutool.poi.excel.style.StyleUtil;
import com.alibaba.excel.metadata.CellData;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.mydemo.entity.domain.AttendanceStatDTO;
import com.example.mydemo.entity.domain.EmployeeClockStatDTO;
import com.example.mydemo.entity.domain.ExcelDTO;
import com.example.mydemo.mapper.AttendanceMapper;
import com.example.mydemo.mapper.ClockMapper;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.poi.ss.usermodel.CellStyle;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.*;
import java.net.URLEncoder;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.stream.Stream;
@Service
public class AttendanceService {

    @Autowired
    private AttendanceMapper attendanceMapper;
    @Autowired
    private ClockMapper clockMapper;
    public List<AttendanceStatDTO> getAttendanceStat(String month) throws ParseException {
        // 1. 解析月份，生成起始和结束时间
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM");
        Date monthDate = sdf.parse(month);
        Calendar cal = Calendar.getInstance();
        cal.setTime(monthDate);
        Date monthStart = cal.getTime();  // 本月第一天00:00:00
        cal.add(Calendar.MONTH, 1);
        cal.add(Calendar.DAY_OF_MONTH, -1);
        Date monthEnd = cal.getTime();    // 本月最后一天23:59:59
        List<AttendanceStatDTO> a = attendanceMapper.count(monthStart, monthEnd);
        int days =calculateWorkingDays(monthStart,monthEnd);
        List<AttendanceStatDTO> normalCount = attendanceMapper.countNormal(days, monthStart, monthEnd);
        for (AttendanceStatDTO x : normalCount){
            for(AttendanceStatDTO n: a){
                x.setMonth(month);
                if(x.getDepartmentId()==n.getDepartmentId()){
                    x.setEarlyLeaveCount(n.getEarlyLeaveCount());
                    x.setLateCount(n.getLateCount());
                    x.setTotalCount(n.getTotalCount());
                    x.setAbnormalCount(n.getTotalCount()-x.getNormalCount());
                    String str = String.valueOf((double) x.getNormalCount() / n.getTotalCount() * 100);
                    if(str.length()>=5){
                        x.setAttendanceRate(str.substring(0,5));
                    }else {
                        x.setAttendanceRate(str);
                    }

                }
            }
        }

        return normalCount;
    }
    private int calculateWorkingDays(Date startDate, Date endDate) {
        // 转换为LocalDate并计算日期范围
        LocalDate start = startDate.toInstant()
                .atZone(ZoneId.systemDefault())
                .toLocalDate();
        LocalDate end = endDate.toInstant()
                .atZone(ZoneId.systemDefault())
                .toLocalDate();

        // 使用Java 8流式计算工作日
        return (int) Stream.iterate(start, date -> date.plusDays(1))
                .limit(ChronoUnit.DAYS.between(start, end) + 1)
                .filter(date -> {
                    DayOfWeek dayOfWeek = date.getDayOfWeek();
                    // 判断是否为周六或周日
                    return !dayOfWeek.equals(DayOfWeek.SATURDAY)
                            && !dayOfWeek.equals(DayOfWeek.SUNDAY);
                })
                .count();
    }
    public void saveAll(List<AttendanceStatDTO> a){
        attendanceMapper.insertOrUpdate(a);
    }
    public List<AttendanceStatDTO> qureyAll(Page<AttendanceStatDTO> page){
        return attendanceMapper.selectList(page,new QueryWrapper<>());
    }
    public Page<AttendanceStatDTO> qureyByMouth(Page<AttendanceStatDTO> page,String month){
        return attendanceMapper.selectPage(page,new QueryWrapper<AttendanceStatDTO>().eq("month",month));
    }
    public void batchInsertOrUpdate(List<AttendanceStatDTO> list){
        attendanceMapper.batchInsertOrUpdate(list);
    }
    public IPage<EmployeeClockStatDTO> getClockStats(
            Page<EmployeeClockStatDTO> page,
            Long departmentId,
            String month
    ) throws ParseException {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM");
        Date monthDate = sdf.parse(month);
        Calendar cal = Calendar.getInstance();
        cal.setTime(monthDate);
        Date monthStart = cal.getTime();  // 本月第一天00:00:00
        cal.add(Calendar.MONTH, 1);
        cal.add(Calendar.DAY_OF_MONTH, -1);
        Date monthEnd = cal.getTime();
        return clockMapper.selectMonthByDepartmentId(page, departmentId, monthStart, monthEnd);
    }
    public void export(HttpServletResponse response,String month,Long departmentId,String departmentName) throws ParseException {
        String path = "d:/testxlsx/"+month+"-"+departmentName+".xlsx";
        try {
            // path是指想要下载的文件的路径
            File file = new File(path);
            if (file.exists()) {
                System.out.println("文件存在");
                // 获取文件名
                String filename = file.getName();
                // 获取文件后缀名
                String ext = filename.substring(filename.lastIndexOf(".") + 1).toLowerCase();

                // 将文件写入输入流
                FileInputStream fileInputStream = new FileInputStream(file);
                InputStream fis = new BufferedInputStream(fileInputStream);
                byte[] buffer = new byte[fis.available()];
                fis.read(buffer);
                fis.close();

                // 清空response
                response.reset();
                // 设置response的Header
                response.setCharacterEncoding("UTF-8");
                //Content-Disposition的作用：告知浏览器以何种方式显示响应返回的文件，用浏览器打开还是以附件的形式下载到本地保存
                //attachment表示以附件方式下载   inline表示在线打开   "Content-Disposition: inline; filename=文件名.mp3"
                // filename表示文件的默认名称，因为网络传输只支持URL编码的相关支付，因此需要将文件名URL编码后进行传输,前端收到后需要反编码才能获取到真正的名称
                response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(filename, "UTF-8"));
                // 告知浏览器文件的大小
                response.addHeader("Content-Length", "" + file.length());
                OutputStream outputStream = new BufferedOutputStream(response.getOutputStream());
                response.setContentType("application/octet-stream");
                outputStream.write(buffer);
                outputStream.flush();
            } else {
                System.out.println("文件不存在");
                Page<EmployeeClockStatDTO> x = new Page<>(1,1000);
                List<EmployeeClockStatDTO> rowlist = getClockStats(x,departmentId,month).getRecords();
                List<ExcelDTO> list = new ArrayList<>();
                rowlist.forEach(e -> {
                    e.setDepartmentName(departmentName);
                    list.add(new ExcelDTO(e));
                });
                //通过工具类创建writer
                ExcelWriter writer = ExcelUtil.getWriter(path);
                //自动列宽
//                writer.autoSizeColumnAll();
                // 在需要的单元格上设置文本格式
//                writer.getStyleSet().set
                writer.addHeaderAlias("employeeId", "员工编号");
                writer.addHeaderAlias("employeeName", "员工姓名");
                writer.addHeaderAlias("departmentId", "部门编号");
                writer.addHeaderAlias("departmentName", "部门名称");
                writer.addHeaderAlias("totalLateDays", "迟到天数");
                writer.addHeaderAlias("totalEarlyDays", "早退天数");
                writer.addHeaderAlias("insufficientDays", "打卡异常天数");
                writer.addHeaderAlias("normalDays", "打卡正常天数");
                writer.getSheet().setColumnWidth(0, 7000);
                writer.getSheet().setColumnWidth(1, 5000);
                writer.getSheet().setColumnWidth(2, 4000);
                writer.getSheet().setColumnWidth(3, 4000);
                writer.getSheet().setColumnWidth(4, 4000);
                writer.getSheet().setColumnWidth(5, 4000);
                writer.getSheet().setColumnWidth(6, 4000);
                writer.getSheet().setColumnWidth(7, 4000);
//跳过当前行，既第一行，非必须，在此演示用
//                writer.passCurrentRow();

//合并单元格后的标题行，使用默认标题样式
                writer.merge(rowlist.size() - 1, "测试标题");
//一次性写出内容，强制输出标题
                writer.write(list, true);
//关闭writer，释放内存
                writer.close();
                // 获取文件名
                String filename = file.getName();
                // 获取文件后缀名
                String ext = filename.substring(filename.lastIndexOf(".") + 1).toLowerCase();

                // 将文件写入输入流
                FileInputStream fileInputStream = new FileInputStream(file);
                InputStream fis = new BufferedInputStream(fileInputStream);
                byte[] buffer = new byte[fis.available()];
                fis.read(buffer);
                fis.close();

                // 清空response
                response.reset();
                // 设置response的Header
                response.setCharacterEncoding("UTF-8");
                //Content-Disposition的作用：告知浏览器以何种方式显示响应返回的文件，用浏览器打开还是以附件的形式下载到本地保存
                //attachment表示以附件方式下载   inline表示在线打开   "Content-Disposition: inline; filename=文件名.mp3"
                // filename表示文件的默认名称，因为网络传输只支持URL编码的相关支付，因此需要将文件名URL编码后进行传输,前端收到后需要反编码才能获取到真正的名称
                response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(filename, "UTF-8"));
                // 告知浏览器文件的大小
                response.addHeader("Content-Length", "" + file.length());
                OutputStream outputStream = new BufferedOutputStream(response.getOutputStream());
                response.setContentType("application/octet-stream");
                outputStream.write(buffer);
                outputStream.flush();
            }

        } catch (IOException ex) {
            ex.printStackTrace();

        }
    }
}
